package com.dreamchaser.familydevice.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.dreamchaser.familydevice.config.device.ExpressionAnalyse;
import com.dreamchaser.familydevice.config.device.infunction.IFunction;
import com.dreamchaser.familydevice.constant.DeviceCache;
import com.dreamchaser.familydevice.dao.ComponentMapper;
import com.dreamchaser.familydevice.dao.DeviceMapper;
import com.dreamchaser.familydevice.domain.dto.DeviceExpression;
import com.dreamchaser.familydevice.po.Component;
import com.dreamchaser.familydevice.po.Device;
import com.dreamchaser.familydevice.service.IDeviceService;
import com.dreamchaser.familydevice.util.CollectionUtils;
import com.dreamchaser.familydevice.util.device.ByteBufUtil;
import com.dreamchaser.familydevice.util.device.ByteHexUtil;
import com.dreamchaser.familydevice.util.device.DeviceDataUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.Channel;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/***
 *                    _ooOoo_
 *                   o8888888o
 *                   88" . "88
 *                   (| -_- |)
 *                    O\ = /O
 *                ____/`---'\____
 *              .   ' \\| |// `.
 *               / \\||| : |||// \
 *             / _||||| -:- |||||- \
 *               | | \\\ - /// | |
 *             | \_| ''\---/'' | |
 *              \ .-\__ `-` ___/-. /
 *           ___`. .' /--.--\ `. . __
 *        ."" '< `.___\_<|>_/___.' >'"".
 *       | | : `- \`.;`\ _ /`;.`/ - ` : | |
 *         \ \ `-. \_ __\ /__ _/ .-` / /
 * ======`-.____`-.___\_____/___.-`____.-'======
 *                    `=---='
 *
 * .............................................
 *          佛祖保佑             永无BUG
 *
 *
 * @author: SJie
 * @Date: 2020/8/16 21:23
 * @description:
 *
 */
@Service
@Slf4j
public class DeviceServiceImpl implements IDeviceService {

    @Autowired
    DeviceMapper deviceMapper;
    @Autowired
    ComponentMapper componentMapper;
    @Autowired
    ExpressionAnalyse expressionAnalyse;
    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Override
    public boolean validDevice(int deviceId) {
        Device device = deviceMapper.selectById(deviceId);
        if (device == null) {
            // todo：微信通知
            return false;
        }
        return true;

    }

    @Override
    public void setComStatus(int deviceId, int comId, int status) {

    }

    @Override
    public void sendInitStatus(int deviceCode, Channel channel) {
        Component component = componentMapper.selectByDeviceId(deviceCode);
        int status = component.getStatusCode();
        if (status == -1) {
            status = 0;
        }
        int[] data = {(component.getComCode() << 4) + status};
        ByteBuf byteBuf = ByteBufUtil.hexToByteBuf(data);
        channel.writeAndFlush(byteBuf);

    }

    @Override
    public void setDeviceStatus(DeviceExpression deviceExpression, byte[] data) {
        for (int i = 1; i < data.length; i++) {

            // 检测是否包含组件
            if (data.length > 2) {
                List<Component> list = componentMapper.selectList(new LambdaQueryWrapper<Component>().eq(Component::getDeviceId, deviceExpression.getDeviceCode()).eq(Component::getComCode, ByteHexUtil.byteToHex(data[i]) >> 4));
                if (list.size() == 0) {
                    continue;
                }
            }

            String varName = DeviceDataUtil.generateVarNameByDeviceAndComStatus(deviceExpression.getDeviceCode(), data[i]);
            try {
                log.info(deviceExpression.getDeviceCode() + "：更新组件设备数据库状态");
                Component component = new Component();
                component.setStatusCode(ByteHexUtil.byteToHex(data[i]) & 0x0f);
                componentMapper.update(component,
                        new LambdaQueryWrapper<Component>().eq(Component::getDeviceId, deviceExpression.getDeviceCode()).eq(Component::getComCode,
                                ByteHexUtil.byteToHex(data[i]) >> 4));
            } catch (Exception e) {
                e.printStackTrace();
            }
            if (!DeviceCache.ComStatusVar.contains(varName)) {
                log.info(deviceExpression.getDeviceCode() + "更新组件设备缓存状态");
                DeviceCache.removeVarByVar(varName.substring(0, varName.length() - 1));
                DeviceCache.ComStatusVar.add(varName);
                log.debug("addComStatusVar:" + varName);
            }

        }

    }

    @Override
    public void refreshDeviceStatus(DeviceExpression deviceExpression, byte data, Channel channel) {
        // 检测是否是主组件动作

//        boolean isMainCom = (ByteHexUtil.byteToHex(data) >> 4) == deviceExpression.getMainComCode();
//        if (isMainCom) {
//            return;
//        }
        String varName = DeviceDataUtil.generateVarNameByDeviceAndComStatus(deviceExpression.getDeviceCode(), data);
        log.debug(varName);
        if (!DeviceCache.ComStatusVar.contains(varName)) {
            log.info(deviceExpression.getDeviceCode() + "：组件状态缓存更新。。。");

            DeviceCache.removeVarByVar(varName.substring(0, varName.length() - 1));
            DeviceCache.ComStatusVar.add(varName);
            log.debug("addComStatusVar:" + varName);


            // 计算表达式并通知设备
            log.info(deviceExpression.getDeviceCode() + "：重新计算表达式。。。");
            expressionAnalyse.notifyDevice(deviceExpression.getDeviceCode(), channel);


        }
        try {
            log.info(deviceExpression.getDeviceCode() + "：组件状态数据库更新。。。");
            Component component = new Component();
            component.setStatusCode(ByteHexUtil.byteToHex(data) & 0x0f);
            componentMapper.update(component,
                    new LambdaQueryWrapper<Component>().eq(Component::getDeviceId, deviceExpression.getDeviceCode()).eq(Component::getComCode,
                            ByteHexUtil.byteToHex(data) >> 4));
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    @Override
    public boolean analyseInternalFunc(int deviceCode, String internalFunc, int data) {
        String[] funcArray = internalFunc.split(",");
        for (String s : funcArray) {
            String funcName = s.split("\\(")[0].toLowerCase();
            IFunction function = ExpressionAnalyse.functionMap.get(funcName);
            if (function != null) {
                // 延时函数
                Pattern pattern = Pattern.compile(funcName + "\\((.*)\\)");
                Matcher matcher = pattern.matcher(s.toLowerCase());
                String value = StringUtils.EMPTY;
                if (matcher.find()) {
                    value = matcher.group(1);
                }
                if (!function.done(deviceCode, value, data)) {
                    return false;
                }
            }
        }
        return true;
    }


}
